package com.example.nettydemo.game;

import com.example.nettydemo.config.GameConfig;
import com.example.nettydemo.entity.Dice;
import com.example.nettydemo.entity.Group;
import com.example.nettydemo.entity.Message;
import com.example.nettydemo.entity.Player;
import com.example.nettydemo.server.NettyChannelHandlerPool;
import com.example.nettydemo.util.MessageUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.Timer;
import java.util.TimerTask;

import static com.example.nettydemo.util.Constants.*;

/**
 * 游戏房间
 *
 * @author WZW
 * @date 2020/5/9
 */
@Data
@EqualsAndHashCode(callSuper = false)
//@Component
public class Room extends TimerTask {

    @JsonIgnore
    private GameConfig gameConfig;

    private String roomId;
    private int lastSec;//倒计时剩余时间
    private int status;//游戏状态
    private int bankerNum;//抢庄次数
    private int smallMoney;//押小金额
    private int bigMoney;//押大金额
    private int pour;//押注次数
    private int online;//押注次数
    private Player banker;//庄家
    private Group smallPlayers;//押小玩家集合
    private Group bigPlayers;//押大玩家集合
    private boolean bankerWin;//庄家赢
    private boolean gameOver;

    public int getOnline() {
        return NettyChannelHandlerPool.getOnlineCount();
    }

    //    @Autowired
    public Room(String roomId, GameConfig gameConfig) {
        this.gameConfig = gameConfig;
        init(roomId);
    }

    public void init(String roomId) {
        this.roomId = roomId;
        this.banker = null;
        this.bankerWin = false;
        this.bankerNum = 0;
        this.bigMoney = 0;
        this.smallMoney = 0;
        this.lastSec = gameConfig.getHogTime().get();
        this.status = STATUS_GETTING_BANKER;//初始状态为抢庄
        this.smallPlayers = new Group();
        this.bigPlayers = new Group();
    }

    /*@Scheduled(fixedRate = 1000)
    public void testTimer() {
        Message message = new Message();
        if (this.lastSec >= 1) {
            //倒计时未结束
            sendGameStatusToClient(message);
            System.out.println("this.lastSec = " + this.lastSec);
            this.lastSec--;
        } else {
            //倒计时结束
//            this.lastSec = 10;
            changeGameStatus(message);
        }
        MessageUtil.sendMessageToALl(message);
    }*/

    //TODO 修改计时器实现方式
    @Override
    public void run() {
        Message message = new Message();
        message.setRoomId(this.roomId);
        if (this.lastSec >= 1) {
            //倒计时未结束
            sendGameStatusToClient(message);
//            System.out.println("this.lastSec = " + this.lastSec);
            this.lastSec--;
        } else {
            //倒计时结束
//            this.lastSec = 10;
            changeGameStatus(message);
        }
        if (!"s_prize_info".equals(message.getType())) {
            //不是开奖信息才需要全部广播
            MessageUtil.sendMessageToALl(message);
        }
        if (gameOver) {
            cancel();
            System.out.println("退出成功");
        }
    }

    /**
     * 开始游戏
     */
    public void startGame() {
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(this, 0, 1000);
    }

    /**
     * 结束游戏
     */
    public void gameOver() {
        this.gameOver = true;
    }

    private void changeGameStatus(Message message) {
        switch (this.status) {
            case STATUS_GETTING_BANKER:
                //抢庄
                startBetIng(message);
                break;
            case STATUS_BETTING:
                //押注
                startPrizeIng(message);
                break;
            case STATUS_PRIZING:
                //准备开奖
                startPrizeEnd(message);
                break;
            case STATUS_PRIZE_END:
                //开奖之后
                init(this.roomId);
                break;
        }
    }

    private void startPrizeEnd(Message message) {
        if (this.banker == null) {
            return;
        }
        if (this.smallPlayers.playerCount() == 0 && this.bigPlayers.playerCount() == 0) {
            return;
        }
        Dice dice = new Dice();
        message.setOne(String.valueOf(dice.getD1()));
        message.setTwo(String.valueOf(dice.getD2()));
        message.setThree(String.valueOf(dice.getD3()));
        message.setType("s_prize_info");
        //TODO 判断输赢

        //豹子，庄家赢
        this.bankerWin = dice.isLeopard();
        if (dice.sum() > 10) {
            //开奖为大
            this.bigPlayers.setWin(true);
            /*if (this.smallPlayers.sumBet() > this.bigPlayers.sumBet()){
                this.bankerWin = true;
            }*/
        } else {
            //开奖为小
            this.smallPlayers.setWin(true);
            /*if (this.smallPlayers.sumBet() < this.bigPlayers.sumBet()){
                this.bankerWin = true;
            }*/
        }
        //庄家赢
        if (this.bankerWin) {
            int prize = this.smallPlayers.sumBet() + this.bigPlayers.sumBet();
            message.setGuid(this.banker.getGuid());
            message.setMsg("你赢了");
            message.setBonus(prize);
            MessageUtil.sendMessageToOne(message);
        } else {
            //大小一方赢
            int prize = Math.abs(smallPlayers.sumBet() - bigPlayers.sumBet());
            if (prize == 0){
                //平局
                message.setMsg("平局");
                message.setBonus(prize);
                MessageUtil.sendMessageToALl(message);
            }else {
                Group winGroup;
                Group loseGroup;
                if (this.smallPlayers.isWin()){
                    winGroup = this.smallPlayers;
                    loseGroup = this.bigPlayers;
                }else {
                    winGroup = this.bigPlayers;
                    loseGroup = this.smallPlayers;
                }
                winGroup.getPlayers().forEach(player -> {
                    message.setGuid(player.getGuid());
                    message.setMsg("你赢了");
                    message.setBonus(prize);
                    MessageUtil.sendMessageToOne(message);
                });
                loseGroup.getPlayers().forEach(player -> {
                    message.setGuid(player.getGuid());
                    message.setMsg("你输了");
                    message.setBonus(-prize);
                    MessageUtil.sendMessageToOne(message);
                });
            }
        }
        this.status = STATUS_PRIZE_END;
    }

    private void startPrizeIng(Message message) {
        if (this.smallPlayers.playerCount() == 0 && this.bigPlayers.playerCount() == 0) {
            //无人押注，重新开始
            init(this.roomId);
            message.setType("s_replay");
            message.setMsg("无人押注，重新开始");
            return;
        }
        this.status = STATUS_PRIZING;
        this.lastSec = 3;
    }

    public synchronized void setBanker(Player banker) {
        if (this.banker == null) {
            this.banker = banker;
        } else {
            if (banker.getBet() > this.banker.getBet()) {
                this.banker = banker;
            }
        }
    }

    private void startBetIng(Message message) {
        if (this.banker == null || this.bankerNum == 0) {
            init(this.roomId);
            message.setMsg("无人抢庄，重新开始");
            message.setType("s_replay");
            return;
        }
        message.setType("s_hog_info");
        message.setHogNickname(this.banker.getName());
        message.setHogMoney(this.banker.getBet());
        System.out.println("message = " + message);
//        message.setRoomId(this.roomId);
        this.status = STATUS_BETTING;
        this.lastSec = gameConfig.getPourTime().get();
    }

    private void sendGameStatusToClient(Message message) {
        message.setType("s_timer");
        message.setTime(this.lastSec);
        message.setOnline(NettyChannelHandlerPool.getOnlineCount());
        switch (this.status) {
            case STATUS_GETTING_BANKER:
                //抢庄
                message.setMsg("抢庄倒计时");
                message.setHog(this.bankerNum);
                break;
            case STATUS_BETTING:
                message.setMsg("押注倒计时");
                message.setSmallMoney(this.smallMoney);
                message.setBigMoney(this.bigMoney);
                //押注
                break;
            case STATUS_PRIZING:
                //准备开奖
                message.setMsg("开奖倒计时");
                break;
            case STATUS_PRIZE_END:
                //开奖

                break;
        }
    }


}
